package com.hfzy.ihk.web.linkcall.biz;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.hfzy.ihk.common.constants.GlobalStatic;
import com.hfzy.ihk.common.core.elasticsearch.ElasticsearchOperation;
import com.hfzy.ihk.common.core.elasticsearch.EsQueryUtils;
import com.hfzy.ihk.common.core.elasticsearch.anotations.BestDoSupport;
import com.hfzy.ihk.common.core.elasticsearch.base.BestDoContextHolder;
import com.hfzy.ihk.common.core.elasticsearch.service.EsBaseServiceImpl;
import com.hfzy.ihk.common.util.Utils;
import com.hfzy.ihk.common.util.http.HttpClientUtils;
import com.hfzy.ihk.common.util.string.StringUtil;
import com.hfzy.ihk.common.web.WebResult;
import com.hfzy.ihk.facade.calldata.service.EsOptRmiService;
import com.hfzy.ihk.facade.linkcall.entity.BusinessTypeBase;
import com.hfzy.ihk.facade.linkcall.entity.task.CallTask;
import com.hfzy.ihk.facade.linkcall.entity.task.CallTaskPhone;
import com.hfzy.ihk.facade.linkcall.enums.CallTaskStatus;
import com.hfzy.ihk.facade.linkcall.enums.LinkCallOperations;
import com.hfzy.ihk.facade.linkcall.enums.LinkCallRedisVersionKey;
import com.hfzy.ihk.facade.linkcall.enums.LinkCallTables;
import com.hfzy.ihk.web.linkcall.constant.RedisKey;
import com.hfzy.ihk.web.linkcall.dao.CallTaskPhoneRepository;
import com.hfzy.ihk.web.linkcall.dao.CallTaskRepository;
import com.hfzy.ihk.web.linkcall.support.annotation.PreProcessParam;
import com.hfzy.ihk.web.linkcall.utils.UserUtils;
import org.elasticsearch.common.UUIDs;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.elasticsearch.repository.ElasticsearchCrudRepository;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.*;

/**
 * call客任务的业务层
 */
@Component
public class CallTaskBiz extends EsBaseServiceImpl<CallTask> {
    private static final Logger logger = LoggerFactory.getLogger(CallTaskBiz.class);

    @Autowired
    CallTaskRepository callTaskRepository;

    @Autowired
    CallTaskPhoneRepository callTaskPhoneRepository;

    @Reference(version = "1.0.0")
    EsOptRmiService esOptRmiService;

    @Autowired
    ElasticsearchTemplate elasticsearchTemplate;

    @Autowired
    RedisTemplate redisTemplate;

    @Value("${callData.http.url}")
    String callDataUrl;

    @Autowired
    CallDataBiz callDataBiz;

    @Override
    protected ElasticsearchCrudRepository getReposity() {
        return callTaskRepository;
    }

    @BestDoSupport
    public WebResult addCallTask(CallTask callTask, List<CallTaskPhone> callTaskPhoneList) {
        WebResult webResult = null;
        Date createTime = new Date();
        String txId = BestDoContextHolder.getTransactionId();
        callTask.setId(UUIDs.base64UUID());
        callTask.setCreateTime(createTime);
        callTask.setCreateUserId(UserUtils.getCurrentUserId()!=null?UserUtils.getCurrentUserId():0l);
        if (txId != null && callTaskPhoneList!=null && !callTaskPhoneList.isEmpty()) {//次要操作
            callTaskPhoneList.forEach(ctp -> {
                ctp.setId(UUIDs.base64UUID());
                ctp.setCallTaskId(callTask.getId());
                ctp.setHadCalled(false);
            });
            ElasticsearchOperation operation = new ElasticsearchOperation(txId,
                    LinkCallTables.CALL_TASK_PHONE.getTableName(),
                    LinkCallOperations.addCallTaskPhones.getOperationName(),
                    callTaskPhoneList);
            BestDoContextHolder.addOperation(operation);
            callTask.setCallNum(callTaskPhoneList.size());
        }
        if (callTask.getStatus() == null) {
            callTask.setStatus(CallTaskStatus.CALLING);
        }
        //主操作
        boolean flag = createDataAndSetVersion(LinkCallRedisVersionKey.TABLE_CALL_TASK,
                LinkCallTables.CALL_TASK,
                callTask.getId(),
                callTask.getVersion(),
                () -> callTaskRepository.save(callTask));
        if (!flag) {
            webResult = new WebResult(GlobalStatic.CODE_N, "保存出错", 0, null, null);
        }
        webResult = new WebResult(GlobalStatic.CODE_1, GlobalStatic.SUCCESS_CHAR, 0, null, null);
        return webResult;
    }

    /**
     * 保存
     * */
    @BestDoSupport
    public  WebResult saveCallTask(CallTask callTask, List<CallTaskPhone> callTaskPhoneList) {
        WebResult webResult = null;
        String txId = BestDoContextHolder.getTransactionId();
        if(callTaskPhoneList!=null && !callTaskPhoneList.isEmpty()){
            callTask.setCallNum(callTask.getCallNum() + callTaskPhoneList.size());
            if (txId != null) {//次要操作
                callTaskPhoneList.forEach(ctp -> {
                    ctp.setId(UUIDs.base64UUID());
                    ctp.setCallTaskId(callTask.getId());
                    ctp.setHadCalled(false);
                });
                ElasticsearchOperation operation = new ElasticsearchOperation(txId,
                        LinkCallTables.CALL_TASK_PHONE.getTableName(),
                        LinkCallOperations.addCallTaskPhones.getOperationName(),
                        callTaskPhoneList);
                BestDoContextHolder.addOperation(operation);
            }
        }
        //主操作
        boolean flag = createDataAndSetVersion(LinkCallRedisVersionKey.TABLE_CALL_TASK,
                LinkCallTables.CALL_TASK,
                callTask.getId(),
                callTask.getVersion(),
                () -> callTaskRepository.save(callTask));
        if (!flag) {
            webResult = new WebResult(GlobalStatic.CODE_N, "保存出错", 0, null, null);
        }
        webResult = new WebResult(GlobalStatic.CODE_1, GlobalStatic.SUCCESS_CHAR, 0, null, null);
        return webResult;
    }


    public BoolQueryBuilder getBoolQueryBuilderByParams(Map<String, String> params) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        Iterator entries = params.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry entry = (Map.Entry) entries.next();
            String key = entry.getKey().toString();
            if (!StringUtil.isEmpty(entry.getValue().toString())) {
                switch (key) {
                    case "taskName":
                        QueryBuilder taskName = EsQueryUtils.wildcardQuery("taskName", "*" + params.get("taskName") + "*");
                        EsQueryUtils.boolQuery(boolQueryBuilder, EsQueryUtils.BoolType.MUST, taskName);
                        break;
                    case "projectName":
                        QueryBuilder projectName = EsQueryUtils.wildcardQuery("projectName", "*" + params.get("projectName") + "*");
                        EsQueryUtils.boolQuery(boolQueryBuilder, EsQueryUtils.BoolType.MUST, projectName);
                        break;
                    case "status":
                        CallTaskStatus callTaskStatus = CallTaskStatus.fromValue(params.get("status"));
                        QueryBuilder status = EsQueryUtils.termQuery("status", callTaskStatus.name());
                        boolQueryBuilder.must(status);
                        break;
                    case "id":
                        QueryBuilder queryBuilder = EsQueryUtils.termQuery("id", params.get("id"));
                        boolQueryBuilder.must(queryBuilder);
                        break;
                    case "packageId":
                        boolQueryBuilder.must(EsQueryUtils.termQuery("packageId.keyword", params.get("packageId")));
                        break;
                    case "createTimeStart":
                        boolQueryBuilder.must(EsQueryUtils.rangeQuery("createTime", params.get("createTimeStart"),
                                null, true, false));
                        break;
                    case "createTimeEnd":
                        boolQueryBuilder.must(EsQueryUtils.rangeQuery("createTime", null,
                                params.get("createTimeEnd"), false, true));
                        break;
                    case "createUserId":
                        boolQueryBuilder.must(EsQueryUtils.termQuery("createUserId",params.get("createUserId")));
                        break;
                    default:
                        break;
                }
            }
        }
        return boolQueryBuilder;
    }

    @PreProcessParam
    public Page<CallTask> queryCallTaskPage(Map<String, String> params) throws Exception {
        logger.debug("queryCallTaskPage param:{}", JSON.toJSONString(params));
        BoolQueryBuilder boolQueryBuilder = getBoolQueryBuilderByParams(params);
        int pageNum = Integer.valueOf(params.get("page")) - 1;
        int pageSize = Integer.valueOf(params.get("pageSize"));
        //添加排序字段
        FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort("createTime").order(SortOrder.DESC);
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder).withSort(fieldSortBuilder).withPageable(PageRequest.of(pageNum, pageSize));
        return callTaskRepository.search(builder.build());
    }

    @PreProcessParam
    public List<CallTask> getCallTaskList(Map<String, String> params){
       /* List<CallTask> callTasks = null;
        logger.debug("getCallTaskList param:{}", JSON.toJSONString(params));
        BoolQueryBuilder boolQueryBuilder = getBoolQueryBuilderByParams(params);
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .build();
        return  elasticsearchTemplate.queryForList(searchQuery,CallTask.class);*/
        List<CallTask> callTasks = null;
        BoolQueryBuilder boolQueryBuilder = getBoolQueryBuilderByParams(params);
        Iterator<CallTask> iterator = callTaskRepository.search(boolQueryBuilder).iterator();
        if (iterator != null) {
            callTasks = new ArrayList<CallTask>();
            while (iterator.hasNext()) {
                CallTask next = iterator.next();
                callTasks.add(next);
            }
        }
        return callTasks;
    }


    public CallTask getCallTaskById(String id){
        Map params = new HashMap();
        params.put("id",id);
        List<CallTask> callTasks = getCallTaskList(params);
        return Utils.getFirst(callTasks);
    }


    /**
     * 功能描述: 通知呼叫任务已经完成(任务中所有号码都已经打完)
     *
     * @param: [callTaskId] 已完成呼叫任务的callTaskId
     * @return: String flag  -1代表调用接口出错,0代表传入的callTaskId为null,1代表成功调用
     * @auther:
     * @date: 2018/9/7
     */

    public String callTaskCompletion(String callTaskId) {

        try {

            //String flag = esOptRmiService.callTaskCompletion(callTaskId);
            String flag = callDataBiz.callTaskCompletion(callTaskId);

            return flag;

        } catch (Exception e) {

            e.printStackTrace();
            logger.error("调用dubbo的呼叫任务完成操作出错", e);
            return "-1";
        }

    }


    public void updateSomeFields(String dataId,Map<String, Object> fieldValueMap){
        callTaskRepository.updateSomeFields(dataId,CallTask.class,fieldValueMap);
    }


    public void addTakePhoneNum(String callTaskId){
        redisTemplate.opsForValue().increment(RedisKey.getTaskPhoneNumRedisKey(callTaskId),1);
    }


    public int getTakePhoneNum(String callTaskId){
        int count = 0;
        Object object = redisTemplate.opsForValue().get(RedisKey.getTaskPhoneNumRedisKey(callTaskId));
        if(object!=null){
            count = (Integer)object;
        }
        return count;
    }


}
